﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using SmartSpace.Core;
using SsTool.Controls.Workflow;
using SmartSpace.Workflow;

namespace SsTool.Controls
{
    /// <summary>
    /// Interaction logic for WorkflowPanel.xaml
    /// </summary>
    public partial class WorkflowPanel : UserControl
    {
        public WorkflowMetadata Workflow
        {
            get { return (WorkflowMetadata)GetValue(WorkflowProperty); }
            set { SetValue(WorkflowProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Workflow.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty WorkflowProperty =
            DependencyProperty.Register("Workflow", typeof(WorkflowMetadata), typeof(WorkflowPanel), new UIPropertyMetadata(default
                (WorkflowMetadata), OnWorkflowPropertyChangedCallback));

        static void OnWorkflowPropertyChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            WorkflowPanel control = sender as WorkflowPanel;

            control.UpdateLayout();
        }

        private ActivityPanel _endPanel;

        private ActivityPanel _selectedPanel;

        Border _alertB = new Border();

        public ActivityMetadata SelectedActivity { get; private set; }

        public event Action<ActivityMetadata> DoubleClick;

        public WorkflowPanel()
        {
            InitializeComponent();
        }

        public void UpdateLayout()
        {
            this._ctlCanvas.Children.Clear();

            System.Diagnostics.Debug.WriteLine("------------------clear!-----------------");
            ActivityMetadata root = Workflow.GetRoot();
            if (root != null)
            {
                ActivityPanel rootPanel = new ActivityPanel();
                rootPanel.Click += new RoutedEventHandler(rootPanel_Click);
                rootPanel.MouseEnter += new MouseEventHandler(rootPanel_MouseEnter);
                rootPanel.DoubleClick += new MouseButtonEventHandler(childPanel_DoubleClick);
                rootPanel.DataContext = root;
                this._ctlCanvas.Children.Add(rootPanel);

                BuildPanel(rootPanel, root);

                rootPanel.UpdateRootPosition(new Point(_ctlCanvas.ActualHeight / 2, 90));

                #region 调整
                //rootPanel.Backup();
                Ajust(rootPanel);
                #endregion
                Ajust2(rootPanel);

                _ctlCanvas.Width = rootPanel.RightX - rootPanel.LeftX;
                _ctlCanvas.Height = rootPanel.BottomY - rootPanel.TopY;

                if (rootPanel.RightX > _ctlCanvas.Width
                    || rootPanel.LeftX < 0)
                {
                    rootPanel.AllMove(-rootPanel.LeftX, 0);
                }

                // 结束点
                _endPanel = new ActivityPanel();
                _ctlCanvas.Children.Add(_endPanel);
                _endPanel.SetCenterPos(new Point(_ctlCanvas.Width / 2, _ctlCanvas.Height + ActivityPanel._height));
                _ctlCanvas.Height += ActivityPanel._height * 2;

                BuildLine(rootPanel);

                _ctlCanvas.Children.Add(_alertB);
                _alertB.BorderBrush = new SolidColorBrush(Colors.Red);
                _alertB.BorderThickness = new Thickness(1);
            }
        }

        private void Ajust(ActivityPanel rootPanel)
        {
            bool isPass = false;
            if (rootPanel.ChildrenPanels.Count == 0)
            {
                return;
            }

            while (!isPass)
            {
                bool isHit = false;
                Queue<ActivityPanel> queue = new Queue<ActivityPanel>();
                queue.Enqueue(rootPanel);
                while (queue.Count > 0)
                {
                    ActivityPanel p = queue.Dequeue();
                    if (!p.Backup())
                    {
                        isHit = true;
                        break;
                    }

                    foreach (ActivityPanel c in p.ChildrenPanels)
                    {
                        queue.Enqueue(c);
                    }
                }

                if (queue.Count == 0 && isHit == false)
                {
                    return;
                }
            }
        }

        private void Ajust2(ActivityPanel rootPanel)
        {
            rootPanel.MoveCenter();
            Queue<ActivityPanel> queue = new Queue<ActivityPanel>();
            queue.Enqueue(rootPanel);
            while (queue.Count > 0)
            {
                ActivityPanel p = queue.Dequeue();
                p.MoveCenter();

                foreach (ActivityPanel c in p.ChildrenPanels)
                {
                    queue.Enqueue(c);
                }
            }
        }

        void childPanel_MouseRightButtonUp(object sender, MouseButtonEventArgs e)
        {
            //ActivityPanel selectedPanel = sender as ActivityPanel;
            //selectedPanel.Backup();
        }

        void rootPanel_MouseEnter(object sender, MouseEventArgs e)
        {
            ActivityPanel selectedPanel = sender as ActivityPanel;
            Canvas.SetTop(_alertB, selectedPanel.TopY);
            Canvas.SetLeft(_alertB, selectedPanel.LeftX);
            _alertB.Width = selectedPanel.RightX - selectedPanel.LeftX;
        }

        void rootPanel_Click(object sender, RoutedEventArgs e)
        {
            if (_selectedPanel != null)
            {
            }
            _selectedPanel = sender as ActivityPanel;
            SelectedActivity = _selectedPanel.DataContext as ActivityMetadata;
        }

        void childPanel_DoubleClick(object sender, MouseButtonEventArgs e)
        {
            if (DoubleClick != null)
            {
                _selectedPanel = sender as ActivityPanel;
                SelectedActivity = _selectedPanel.DataContext as ActivityMetadata;
                DoubleClick(SelectedActivity);
            }
        }

        private void BuildPanel(ActivityPanel parentPanel, ActivityMetadata parentActivity)
        {
            //if (parentActivity.NextActivities == null)
            //{
            //    return;
            //}
            //for (int index = 0; index < parentActivity.NextActivities.Count; index++)
            //{
            //    ActivityMetadata childActivity = parentActivity.NextActivities[index];

            //    ActivityPanel childPanel = new ActivityPanel();
            //    childPanel.Click += new RoutedEventHandler(rootPanel_Click);
            //    childPanel.MouseEnter += new MouseEventHandler(rootPanel_MouseEnter);
            //    childPanel.MouseRightButtonUp += new MouseButtonEventHandler(childPanel_MouseRightButtonUp);
            //    childPanel.DoubleClick += new MouseButtonEventHandler(childPanel_DoubleClick);
            //    childPanel.Depth = childActivity.Depth;
            //    childPanel.Index = index;
            //    childPanel.DataContext = childActivity;

            //    childPanel.SetParent(parentPanel);

            //    this._ctlCanvas.Children.Add(childPanel);

            //    BuildPanel(childPanel, childActivity);
            //}
        }

        private void BuildLine(ActivityPanel parentPanel)
        {
            Point outPos = parentPanel.GetOutPos();
            if (parentPanel.ChildrenPanels.Count == 0)
            {
                Point inPos = this._endPanel.GetInPos();

                Line line = new Line();
                line.X1 = outPos.X;
                line.Y1 = outPos.Y;
                line.X2 = inPos.X;
                line.Y2 = inPos.Y;


                line.Stroke = Brushes.Black;
                line.StrokeThickness = 1;

                this._ctlCanvas.Children.Add(line);
            }
            else
            {
                foreach (ActivityPanel child in parentPanel.ChildrenPanels)
                {
                    Point inPos = child.GetInPos();

                    Line line = new Line();
                    line.X1 = outPos.X;
                    line.Y1 = outPos.Y;
                    line.X2 = inPos.X;
                    line.Y2 = inPos.Y;


                    line.Stroke = Brushes.Black;
                    line.StrokeThickness = 1;

                    this._ctlCanvas.Children.Add(line);

                    BuildLine(child);
                }
            }
        }
    }
}
